package com.hqd.ch03.v2;

import com.hqd.ch03.v2.io.Resource;
import org.apache.commons.beanutils.BeanUtils;
import org.apache.commons.collections.CollectionUtils;
import org.dom4j.Document;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;

import java.io.IOException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class SpringImitationV2 {
    /**
     * 对象缓存
     */
    private Map<String, Object> bdMap = new HashMap<>();

    public SpringImitationV2(Resource resource) {
        this.init(resource);
    }

    public <T> T getBean(String name, Class<T> clazz) {
        return (T) bdMap.get(name);
    }

    /**
     * 初始化bean
     *
     * @param bean
     * @param properties
     */
    private void initBean(Object bean, List<Element> properties) {
        try {
            properties.forEach(property -> {
                String name = property.attributeValue("name");
                String value = property.attributeValue("value");
                try {
                    BeanUtils.setProperty(bean, name, value);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            });
        } catch (Exception e) {
            e.printStackTrace();
        }

    }

    /**
     * 创建bean对象
     *
     * @param beanEles
     */
    private void createBeans(List<Element> beanEles) {
        beanEles.forEach(beanEle -> {
            String className = beanEle.attributeValue("class");
            Object bean = createBean(className);
            List<Element> properties = beanEle.elements("property");
            if (CollectionUtils.isNotEmpty(properties)) {
                initBean(bean, properties);
            }
            bdMap.put(beanEle.attributeValue("id"), bean);
        });
    }

    private Object createBean(String className) {
        try {
            return Class.forName(className).getConstructor().newInstance();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 加载配置
     *
     * @param resource
     * @return
     */
    private Document loadConfig(Resource resource) {
        SAXReader reader = new SAXReader();
        try {
            return reader.read(resource.getInputStream());
        } catch (Exception e) {
            throw new RuntimeException(e);
        } finally {
            try {
                resource.getInputStream().close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * 解析配置文件
     *
     * @param document
     * @return
     */
    private List<Element> parseConfig(Document document) {
        Element rootElement = document.getRootElement();
        return rootElement.elements("bean");
    }

    private void init(Resource resource) {
        Document document = loadConfig(resource);
        List<Element> beanEles = parseConfig(document);
        createBeans(beanEles);
    }
}
